pub mod rpc_client {
    tonic::include_proto!("config_monitor_a");
}

use std::path::PathBuf;

use anyhow::Ok;
use walkdir::WalkDir;

use crate::modifymsg::ModifyMsg;

/// 维护agent的信息
/// 提供call agent的方法
#[derive(Debug, Clone)]
pub struct Agent {
    /// agent的rpc地址
    addr: String,
}

impl Agent {
    pub fn new(addr: String) -> Self {
        Agent {
            addr: "http://".to_string() + &addr,
        }
    }

    /// 向这个agent更新文件，rpc call
    pub async fn sync_config_file(&self, msg: ModifyMsg) -> anyhow::Result<()> {
        // 向这个agent的rpc地址 call
        let config_file_path_agent = msg.file_path_agent.display().to_string();
        let request = match msg.delta {
            git2::Delta::Deleted => {
                // 删除文件
                tonic::Request::new(rpc_client::SyncConfigRequest {
                    config_file_path_agent,
                    config_file_content: "".to_string(),
                    action: rpc_client::ConfigFileAction::Delete as i32,
                })
            }
            git2::Delta::Added | git2::Delta::Modified => {
                tonic::Request::new(rpc_client::SyncConfigRequest {
                    config_file_path_agent,
                    config_file_content: std::fs::read_to_string(&msg.file_path_server)?,
                    action: rpc_client::ConfigFileAction::Sync as i32,
                })
            }
            _ => {
                todo!("delta={:?} not supported", msg.delta);
            }
        };
        #[cfg(debug_assertions)]
        println!(
            "agent[{:?}] sync_config_file REQUEST={:?}",
            self.addr, request
        );

        match rpc_client::config_monitor_a_client::ConfigMonitorAClient::connect(self.addr.clone())
            .await
        {
            std::result::Result::Ok(mut client) => {
                let _response = client.sync_config(request).await?;
                #[cfg(debug_assertions)]
                println!(
                    "agent[{:?}] sync_config_file RESPONSE={:?}",
                    self.addr, _response
                );
                Ok(())
            }
            std::result::Result::Err(e) => {
                anyhow::bail!("agent[{:?}] sync_config_file failed: {:?}", self.addr, e);
            }
        }
    }

    /// agent向server注册后，server会调用这个方法，将repo_path下的文件同步到agent
    const APPLY_COMMAND_PATH: &'static str = "/tmp/ConfigMoniter/apply_command.json";
    pub async fn init_files(&self, repo_path: String) -> anyhow::Result<()> {
        // 遍历repo_path下的文件，逐个调用sync_config_file

        // 补丁：先同步APPLY_COMMAND_PATH
        let apply_command_path = PathBuf::from(repo_path.clone() + Self::APPLY_COMMAND_PATH);
        let msg = ModifyMsg {
            file_path_server: apply_command_path.clone(),
            file_path_agent: PathBuf::from(Self::APPLY_COMMAND_PATH),
            delta: git2::Delta::Added,
        };
        self.sync_config_file(msg).await?;

        let walker = WalkDir::new(&repo_path).into_iter();
        for entry in walker
            .filter_map(
                |e| e.ok(), //可访问
            )
            .filter(|e| {
                !e.path().to_str().unwrap().contains(".git") //判断这个路径中是否有.git
            })
            .filter(
                |e| e.file_type().is_file(), // 判断是否是文件
            )
        {
            let file_path_server = entry.path().to_path_buf();
            //从/开始，绝对路径
            let file_path_agent = PathBuf::from(format!(
                "/{}",
                file_path_server
                    .strip_prefix(&repo_path)
                    .unwrap()
                    .to_string_lossy()
            ));
            let delta = git2::Delta::Added;
            let msg = ModifyMsg {
                file_path_server,
                file_path_agent,
                delta,
            };
            self.sync_config_file(msg).await?;
        }
        Ok(())
    }
}
